package com.sskj.lib.util;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.ImmutableList;
import com.sskj.common.util.MD5Util;

import org.bitcoinj.crypto.ChildNumber;
import org.bitcoinj.crypto.DeterministicHierarchy;
import org.bitcoinj.crypto.DeterministicKey;
import org.bitcoinj.crypto.HDKeyDerivation;
import org.bitcoinj.crypto.MnemonicCode;
import org.bitcoinj.wallet.DeterministicSeed;
import org.spongycastle.crypto.digests.KeccakDigest;
import org.spongycastle.jcajce.provider.digest.Keccak;
import org.web3j.crypto.CipherException;
import org.web3j.crypto.Credentials;
import org.web3j.crypto.ECKeyPair;
import org.web3j.crypto.Keys;
import org.web3j.crypto.RawTransaction;
import org.web3j.crypto.TransactionEncoder;
import org.web3j.crypto.Wallet;
import org.web3j.crypto.WalletFile;
import org.web3j.crypto.WalletUtils;
import org.web3j.protocol.ObjectMapperFactory;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.Web3jFactory;
import org.web3j.protocol.core.DefaultBlockParameterName;
import org.web3j.protocol.http.HttpService;
import org.web3j.utils.Convert;
import org.web3j.utils.Numeric;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.List;

public class ETHUtil {

    private static Web3j mWeb3j = Web3jFactory.build(new HttpService("https://ropsten.infura.io/1UoO4I/"));

    /**
     * 创建助记词
     *
     * @return
     */
    public static List<String> createMnemonics() {
        try {
            SecureRandom secureRandom = new SecureRandom();
            byte[] entropy = new byte[DeterministicSeed.DEFAULT_SEED_ENTROPY_BITS / 8];
            secureRandom.nextBytes(entropy);
            return MnemonicCode.INSTANCE.toMnemonic(entropy);
        } catch (Exception e) {
            System.out.println("ETH::::生成助记词失败" + e.toString());
            e.printStackTrace();
        }
        return new ArrayList<>();

    }

    //m / 44' / 60' / 0' / 0
//Hardened意思就是派生加固，防止获取到一个子私钥之后可以派生出后面的子私钥
//必须还有上一级的父私钥才能派生
    public static final ImmutableList<ChildNumber> BIP44_ETH_ACCOUNT_ZERO_PATH =
            ImmutableList.of(new ChildNumber(44, true), new ChildNumber(60, true),
                    ChildNumber.ZERO_HARDENED, ChildNumber.ZERO);

    //通过助记词生成HD钱包
    public static String createWallet(List<String> words, String pwd) {

        byte[] seed = MnemonicCode.toSeed(words, "");
        DeterministicKey masterPrivateKey = HDKeyDerivation.createMasterPrivateKey(seed);
        DeterministicHierarchy deterministicHierarchy = new DeterministicHierarchy(masterPrivateKey);
        // m / 44' / 60' / 0' / 0 / 0
        DeterministicKey deterministicKey = deterministicHierarchy
                .deriveChild(BIP44_ETH_ACCOUNT_ZERO_PATH, false, true, new ChildNumber(0));
        byte[] bytes = deterministicKey.getPrivKeyBytes();
        ECKeyPair keyPair = ECKeyPair.create(bytes);
        try {

            WalletFile walletFile = Wallet.createLight(MD5Util.getMd5Value(pwd), keyPair);
            String address = walletFile.getAddress();
            return "0x" + address;
        } catch (CipherException e) {
            e.printStackTrace();
        }
        return "";
    }

    /**
     * 导出KeyStore
     *
     * @param wallet
     * @return
     */
    public static String exportKeyStore(WalletFile wallet) {
        try {
            ObjectMapper objectMapper = ObjectMapperFactory.getObjectMapper();
            return objectMapper.writeValueAsString(wallet);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 导出私钥
     *
     * @param wallet
     * @return
     */
    public String exportPrivateKey(WalletFile wallet, String pwd) {
        try {
            ECKeyPair ecKeyPair = Wallet.decrypt(MD5Util.getMd5Value(pwd), wallet);
            BigInteger privateKey = ecKeyPair.getPrivateKey();
            return Numeric.toHexStringNoPrefixZeroPadded(privateKey, Keys.PRIVATE_KEY_LENGTH_IN_HEX);
        } catch (CipherException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取余额
     *
     * @param address
     * @return
     */
    public static String getBalance(String address) {
        try {

            BigInteger balanceWei = mWeb3j.ethGetBalance(address, DefaultBlockParameterName.LATEST).send().getBalance();
            BigDecimal balance = Convert.fromWei(balanceWei.toString(), Convert.Unit.ETHER);
            return balance.toPlainString();
        } catch (Exception e) {

        }
        return null;
    }
//    public static String transfer(String fromAddress,String toAddress,String num,String gasLimit,String pwd){
//        BigInteger transactionCount = mWeb3j.ethGetTransactionCount(fromAddress, DefaultBlockParameterName.LATEST).send().getTransactionCount();
//        BigInteger gasPriceBig = mWeb3j.ethGasPrice().send().getGasPrice();
//        BigInteger gasLimitBig = new BigInteger(gasLimit);
//        BigDecimal value = Convert.toWei(num, Convert.Unit.ETHER);
//        RawTransaction etherTransaction = RawTransaction.createEtherTransaction(transactionCount, gasPriceBig, gasLimitBig, toAddress, value.toBigInteger());
//        ECKeyPair ecKeyPair = Wallet.decrypt(MD5Util.getMd5Value(pwd), mWalletFile);
//        Credentials credentials = Credentials.create(ecKeyPair);
//        byte[] bytes = TransactionEncoder.signMessage(etherTransaction, credentials);
//        String hexValue = Numeric.toHexString(bytes);
//        String transactionHash = mWeb3j.ethSendRawTransaction(hexValue).send().getTransactionHash();
//    }

}
